package web

import (
	"gitee.com/kristas/booting-go/framework/core/bean"
	"gitee.com/kristas/booting-go/framework/core/statement/types"
	"net/http"
	"reflect"
)

// Controller web restful api controller
type Controller interface {
	bean.Bean
	Group() string
}

// FsController static assets controller
type FsController interface {
	Controller
	Compile() bool
}

// Server web server container
type Server interface {
	bean.Bean
	RegisterEndpoint(endpoint Endpoint)
	FsHandler(prefix, dir string)
	ListenAndServe(port int) error
}

// FS is file system mapping
type FS struct{}

// RestMethod is restful mapping interface
type RestMethod interface {
	GetType() string
}

type Endpoint interface {
	GetApiInfo() ApiInfo
	GetServiceMethod() ServiceMethod
	Handler(adapter ParamAdapter, handler func(result interface{}) error)
}

type Service func() error

type FilterChain interface {
	GetFilter() Filter
	SetNext(chain FilterChain)
	GetNext() FilterChain
	DoFilter(w http.ResponseWriter, r *http.Request) error
	SetService(service Service)
	DoService() error
}

type Filter interface {
	bean.Bean
	Order() int
	UrlPatterns() []string
	DoFilter(w http.ResponseWriter, r *http.Request, chain FilterChain) error
}

type Configure struct {
	types.AutoConfigure `prefix:"application.web"`
	Charset             string `yaml:"charset"`
}

const (
	Path      = "path"
	Query     = "query"
	Body      = "body"
	Header    = "header"
	Form      = "form"
	Multipart = "multipart"
	Context   = "context"
	Request   = "request"
	Response  = "response"
	Stream    = "stream"
)

var (
	SourceDefine  = []string{Path, Query, Body, Form, Header, Multipart, Context, Request, Response, Stream}
	DefaultSource = Query
)

type ApiInfo interface {
	GetHttpMethod() string
	GetURL() string
	GetDescription() string
	GetParams() []Param
	GetField() reflect.StructField
	GetMethodName() string
	GetMeta(tag string) string
}

type Param interface {
	GetName() string
	GetSource() string
	GetSpecifyType() string
	GetType() reflect.Type
	SetType(t reflect.Type)
}

type ServiceMethod interface {
	GetMethod() *reflect.Method
	GetValue() *reflect.Value
}

type ParamAdapter interface {
	GetStringFromPath(name string) (string, error)
	GetRequest() *http.Request
	GetResponseWriter() http.ResponseWriter
}

type FeignClient interface {
	bean.Bean
	Name() string
	Url() string
	Path() string
}
